package cn.t.facade.order;


import cn.t.constants.CommonConstants;
import cn.t.constants.ParamConstants;
import cn.t.constants.ResponseError;
import cn.t.converter.order.OrderModelConverter;
import cn.t.converter.order.OverPickupRecordDTOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.facade.FacadeImpl;
import cn.t.core.mode.PageInfoDTO;
import cn.t.core.mode.PageQueryDTO;
import cn.t.dto.order.OrderQueryRequest;
import cn.t.dto.order.OverPickupOrderDTO;
import cn.t.dto.order.OverPickupRecordDTO;
import cn.t.dto.user.RoleSkuDTO;
import cn.t.dto.user.SkuQtyDTO;
import cn.t.enums.OverPickupTypeEnum;
import cn.t.enums.TimeLimitTypeEnum;
import cn.t.enums.order.WorkLineStatusEnum;
import cn.t.facade.android.AndroidSessionFacade;
import cn.t.facade.user.RoleSkuFacade;
import cn.t.model.order.OrderDO;
import cn.t.model.order.OrderDetailDO;
import cn.t.model.order.OverPickNumDO;
import cn.t.model.order.OverPickupRecordDO;
import cn.t.model.order.OverPickupRecordVO;
import cn.t.model.order.WorkOrderDO;
import cn.t.model.order.WorkOrderDetailDO;
import cn.t.service.order.OverPickupRecordService;
import cn.t.service.order.WorkOrderDetailService;
import cn.t.service.order.WorkOrderService;
import cn.t.service.user.CustomerFirmService;
import cn.t.service.user.ParticipantRoleService;
import cn.t.utils.DateUtil;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 超领记录表
 *
 * @author t
 * @since 2024-05-24 10:19:34
 */
@Slf4j
@Service
@AllArgsConstructor
public class OverPickupRecordFacade extends FacadeImpl<OverPickupRecordDTO, OverPickupRecordDO, OverPickupRecordDTOConverter, OverPickupRecordService> {
    /**
     * 获取订单分页列表
     */

    public PageInfoDTO<OverPickupOrderDTO> overPickupRecord(PageQueryDTO<OrderQueryRequest> req) {
        List<OverPickupRecordVO> list = service.queryOverPickupRecordList(req.getParam(), req.getStart(), req.getPageSize());
        List<String> workOrderSnList = list.stream().map(OverPickupRecordVO::getWorkOrderSn).filter(Objects::nonNull).distinct().collect(Collectors.toList());

        //工单信息当前领用数据判断
        Map<String, Long> firstOverPickup = getFirstOverPickup(workOrderSnList);
        List<OverPickupOrderDTO> collect = getOverPickupOrderList(list, firstOverPickup);
        return new PageInfoDTO<>(req.getPageNo(), req.getPageSize(), service.countQuery(req.getParam()), collect);
    }

    public List<OverPickupRecordVO> exportPageList(OrderQueryRequest req) {
        // 计算需要查询的总页数
        int count = (int) Math.ceil((double) ParamConstants.EXPORTPAGEMAXSIZE / ParamConstants.PAGE_MAX_SIZE);
        // 查询第一页数据
        List<OverPickupRecordVO> list = service.queryOverPickupRecordList(req, ParamConstants.INT_0, ParamConstants.PAGE_MAX_SIZE);
        // 如果第一页数据数量小于每页最大数量，直接返回第一页数据
        if (list.size() < ParamConstants.PAGE_MAX_SIZE) {
            return list;
        }
        List<OverPickupRecordVO> overPickupOrderAll = new ArrayList<>(list);
        // 从第二页开始查询，并正确设置查询的起始位置
        for (int j = 1; j < count; j++) {
            // 正确设置查询的起始位置
            List<OverPickupRecordVO> list1 = service.queryOverPickupRecordList(req, j, ParamConstants.PAGE_MAX_SIZE);
            // 如果查询结果等于每页最大数量，说明还有更多数据，继续添加到结果集中
            if (list1.size() == ParamConstants.PAGE_MAX_SIZE) {
                overPickupOrderAll.addAll(list1);
            } else {
                break;
            }
        }

        return overPickupOrderAll;
    }

    /**
     * 导出
     */
    public List<OverPickupOrderDTO> exportList(OrderQueryRequest req) {
        //最高50000条数据 每次取5000分页获取
        List<OverPickupRecordVO> list = exportPageList(req);
        List<String> workOrderSnList = list.stream().map(OverPickupRecordVO::getWorkOrderSn).filter(Objects::nonNull).distinct().collect(Collectors.toList());

        //工单信息当前领用数据判断
        Map<String, Long> firstOverPickup = getFirstOverPickup(workOrderSnList);
        return getOverPickupOrderList(list, firstOverPickup);
    }

    private List<OverPickupOrderDTO> getOverPickupOrderList(List<OverPickupRecordVO> list, Map<String, Long> firstOverPickup) {
        List<Long> firmIds = list.stream().map(OverPickupRecordVO::getFirmId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        //用户信息

        Map<Long, String> firmIdNameMap = new HashMap<>();
        if (firmIds.size() > 0) {
            firmIdNameMap = this.customerFirmService.getFirmIdNameMap(firmIds);
        }
        Map<Long, String> finalFirmIdNameMap = firmIdNameMap;
        return list.stream().map(o1 -> {
            OverPickupOrderDTO overPickupOrderDTO = converter.do2DtoBean(o1);
            overPickupOrderDTO.setGmtCreateStr(DateUtil.setTime(o1.getGmtCreated()));
            overPickupOrderDTO.setFirmName(finalFirmIdNameMap.get(o1.getFirmId()));
            overPickupOrderDTO.setTimeLimitTypeStr(TimeLimitTypeEnum.getNameByCode(overPickupOrderDTO.getTimeLimitType()));
            overPickupOrderDTO.setCurrentOverPick(o1.getOverQty());
            if (o1.getQuantityLimit() < 0) {
                overPickupOrderDTO.setQuantityLimitStr(TimeLimitTypeEnum.NO_LIMIT.getName());
            } else {
                overPickupOrderDTO.setQuantityLimitStr(String.valueOf(o1.getQuantityLimit()));
            }

            if (ObjectUtils.isEmpty(o1.getType())) {
                return overPickupOrderDTO;
            }


            switch (o1.getType()) {
                case 1:
                    overPickupOrderDTO.setTypeStr(OverPickupTypeEnum.PERMISSION_GROUP.getName());
                    return overPickupOrderDTO;
                case 2:
                    overPickupOrderDTO.setTypeStr(OverPickupTypeEnum.ORDER.getName());
                    Long id = 0L;
                    if (o1.getWorkOrderSn() != null) {
                        id = firstOverPickup.get(o1.getWorkOrderSn().concat(o1.getSkuCode()));
                    }
                    if (!Objects.equals(o1.getId(), id)) {
                        overPickupOrderDTO.setCurrentOverPick(o1.getPickupQty());
                    } else {
                        overPickupOrderDTO.setCurrentOverPick(o1.getOverQty());
                    }
                    return overPickupOrderDTO;
                default:
                    return overPickupOrderDTO;
            }
        }).collect(Collectors.toList());
    }

    /**
     * 多次领用 ，对领用单的当前领用数量处理
     *
     * @param workOrderSnList
     * @return
     */
    public Map<String, Long> getFirstOverPickup(List<String> workOrderSnList) {
        //overPickupRecordDOS 分组根据sku和工单号分组，获取id最小的数据
        List<OverPickupRecordDO> overPickupRecordList = service.queryOverPickupByWorkOrderSn(workOrderSnList);
        Map<String, Optional<OverPickupRecordDO>> groupedRecords = overPickupRecordList.stream()
                .collect(Collectors.groupingBy(
                        record -> record.getSkuCode() + "_" + record.getWorkOrderSn(),
                        Collectors.minBy(Comparator.comparingLong(OverPickupRecordDO::getId))
                ));

        // 将Optional转换为实际对象列表
        return groupedRecords.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().get().getId()
                ));
    }

    public List<OverPickupRecordDO> overPickingSku(List<SkuQtyDTO> skuRoleList, OrderDO orderDO, List<OrderDetailDO> orderDetailList) {
        Map<String, Integer> pickNumMapBySku = orderDetailList.stream().collect(Collectors.groupingBy(OrderDetailDO::getSkuCode, Collectors.summingInt(OrderDetailDO::getQty)));
        Map<String, OrderDetailDO> detailMap = orderDetailList.stream().collect(Collectors.toMap(OrderDetailDO::getSkuCode, Function.identity(), (a, b) -> b));
        Map<String, SkuQtyDTO> roleSkuMap = skuRoleList.stream().collect(Collectors.toMap(SkuQtyDTO::getSkuCode, Function.identity(), (v1, v2) -> v2));
        Map<String, RoleSkuDTO> skuRoleMap = roleSkuFacade.findSkuByParticipantId(orderDO.getFirmId(), orderDO.getParticipantId(), orderDO.getDeviceId()).stream().collect(Collectors.toMap(RoleSkuDTO::getSkuCode, Function.identity(), (v1, v2) -> v2));

        ArrayList<OverPickupRecordDO> overPickupRecordList = new ArrayList<>();
        for (Map.Entry<String, Integer> skuQty : pickNumMapBySku.entrySet()) {
            Integer qty = skuQty.getValue();
            String skuCode = skuQty.getKey();
            RoleSkuDTO roleSkuDTO = skuRoleMap.get(skuCode);
            OrderDetailDO orderDetailDO = detailMap.get(skuCode);

            //sku没有权限 超领
            if (roleSkuDTO == null || ObjectUtils.isEmpty(TimeLimitTypeEnum.getEnum(roleSkuDTO.getLimitedType()))) {
                //记录超领数据
                OverPickupRecordDO overPickupOrder = OrderModelConverter.createOverPickupOrder(qty,
                        qty, null, TimeLimitTypeEnum.NO_LIMIT, 0, OverPickupTypeEnum.PERMISSION_GROUP, orderDetailDO);
                overPickupOrder.setFirmId(orderDO.getFirmId());
                overPickupRecordList.add(overPickupOrder);
                continue;
            }
            //sku数量限制
            Integer limitedQuantity = roleSkuDTO.getLimitedQuantity();
            //时间限制为空
            TimeLimitTypeEnum anEnum = TimeLimitTypeEnum.getEnum(roleSkuDTO.getLimitedType());
            if (roleSkuDTO.getLimitedType() < 0 || limitedQuantity == -1) {
                // 不限制
                continue;
            }

            //获取历史领料记录（不包含本次）
            Integer actQty = roleSkuMap.get(skuCode).getPickQuantity();
            //是否超领取判断
            if (OrderModelConverter.isOverPickup(qty, actQty, limitedQuantity)) {
                int overNum = OrderModelConverter.getOverNum(qty, actQty, limitedQuantity);
                //记录超领数据
                OverPickupRecordDO overPickupOrder = OrderModelConverter.createOverPickupOrder(qty,
                        overNum, null, anEnum, limitedQuantity, OverPickupTypeEnum.PERMISSION_GROUP, orderDetailDO);
                overPickupOrder.setFirmId(orderDO.getFirmId());
                overPickupRecordList.add(overPickupOrder);
            }
        }
        return overPickupRecordList;
    }


    /**
     * 判断是否超领取
     *
     * @param orderBean 订单
     * @return 超领列表
     */
    public OverPickNumDO checkOverPickupAndUpdate(OrderDO orderBean, List<OrderDetailDO> orderDetailList, Boolean session) {


        String workOrderSn = orderBean.getWorkOrderSn();
        String orderSn = orderBean.getOrderSn();
        if (orderSn == null) {
            return new OverPickNumDO();
        }

        //判断是否是客户工单，非客户工单走商品权限
        if (ObjectUtils.isEmpty(workOrderSn)) {
            return getDayOverPickNumDO(orderBean, orderDetailList, session);
        }
        //查询工单信息
        WorkOrderDO workOrderDO = new WorkOrderDO();
        workOrderDO.setWorkOrderSn(workOrderSn);
        List<WorkOrderDO> byModel = workOrderService.findByModel(workOrderDO, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);
        if (!ObjectUtils.isEmpty(byModel)) {
            OverPickNumDO overPickNumDO = new OverPickNumDO();
            WorkOrderDO workOrder1 = byModel.get(0);
            WorkOrderDetailDO workOrderDetailReq = new WorkOrderDetailDO();
            workOrderDetailReq.setWorkOrderSn(workOrder1.getWorkOrderSn());
            List<WorkOrderDetailDO> workOrderDetailList = workOrderDetailService.findByModel(workOrderDetailReq, CommonConstants.ZERO, Integer.MAX_VALUE, null, null);
            if (ObjectUtils.isEmpty(workOrderDetailList)) {
                throw new BizException(ResponseError.ORDER_GOODS_NOT_FOUND, ResponseError.ORDER_GOODS_NOT_FOUND.getName());
            }
            Map<String, WorkOrderDetailDO> workOrderDetailMap = workOrderDetailList.stream().collect(Collectors.toMap(WorkOrderDetailDO::getSkuCode, Function.identity()));
            // 工单记录超领信息
            List<OverPickupRecordDO> overPickupRecordWorkList = processWorkerOverPick(orderBean, orderDetailList, workOrderDetailMap);
            overPickNumDO.setWorkOrder1(workOrder1);
            overPickNumDO.setWorkOrderDetailMap(workOrderDetailMap);
            overPickNumDO.setOverPickupList(overPickupRecordWorkList);
            return overPickNumDO;
        } else {
            log.warn("工单查询异常 {}", workOrderSn);
        }

        return new OverPickNumDO();
    }

    private OverPickNumDO getDayOverPickNumDO(OrderDO orderBean, List<OrderDetailDO> orderDetailList, Boolean session) {
        OverPickNumDO overPickNumDO = new OverPickNumDO();
        //判断可用商品数量
        List<SkuQtyDTO> skuRoleList = androidSessionFacade.getDayOverPickNumSession(orderBean, session);
        List<OverPickupRecordDO> overPickupRecordS = overPickingSku(skuRoleList, orderBean, orderDetailList);
        if (!ObjectUtils.isEmpty(overPickupRecordS)) {
            overPickNumDO.setOverPickupList(overPickupRecordS);
        }
        return overPickNumDO;
    }

    public void addOverPick(OverPickNumDO overPickNumDO, OrderDO orderBean) {
        log.info("更新工单状态 {}", JSON.toJSONString(overPickNumDO));
        if (!ObjectUtils.isEmpty(overPickNumDO.getOverPickupList())) {
            overPickNumDO.getOverPickupList().forEach(overPickupRecordDO -> overPickupRecordDO.setWorkOrderSn(orderBean.getWorkOrderSn()));
            //保存超领记录
            overPickNumDO.getOverPickupList().forEach(overPickupRecordDO ->{overPickupRecordDO.setCreator(orderBean.getCreator());
                overPickupRecordDO.setModifier(orderBean.getModifier());
            } );
            service.addBatch( overPickNumDO.getOverPickupList());
        }
        if (!ObjectUtils.isEmpty(overPickNumDO.getWorkOrderDetailMap()) && !ObjectUtils.isEmpty(overPickNumDO.getWorkOrder1())) {

            //更新工单状态
            workOrderService.updateWorkStatus(new ArrayList<>(overPickNumDO.getWorkOrderDetailMap().values()), overPickNumDO.getWorkOrder1());
        }
    }

    private List<OverPickupRecordDO> processWorkerOverPick(OrderDO orderDO, List<OrderDetailDO> orderDetailList, Map<String, WorkOrderDetailDO> workOrderDetailMap) {
        Map<String, Integer> pickNumMapBySku = orderDetailList.stream().collect(Collectors.groupingBy(OrderDetailDO::getSkuCode, Collectors.summingInt(OrderDetailDO::getQty)));
        Map<String, OrderDetailDO> detailMap = orderDetailList.stream().collect(Collectors.toMap(OrderDetailDO::getSkuCode, Function.identity(), (a, b) -> b));

        List<OverPickupRecordDO> overPickupRecordList = new ArrayList<>();
        pickNumMapBySku.forEach((skuCode, qty) -> {
            WorkOrderDetailDO workOrderLineBean = workOrderDetailMap.get(skuCode);
            OrderDetailDO orderDetailDO = detailMap.get(skuCode);
            //判断转单数据是否发生超领&&并且更新工单领用明细
            //1.工单中未有转单的sku
            if (workOrderLineBean == null) {
                //记录超领数据
                OverPickupRecordDO overPickupOrder = OrderModelConverter.createOverPickupOrder(qty,
                        qty, orderDO.getWorkOrderSn(), TimeLimitTypeEnum.NO_LIMIT, 0, OverPickupTypeEnum.ORDER, orderDetailDO);
                overPickupOrder.setFirmId(orderDO.getFirmId());
                overPickupRecordList.add(overPickupOrder);

            } else {
                //2.超出计划领用数量   （转单数量+之前已领数据）> 工单明细申请数量
                Integer actQty = workOrderLineBean.getActQty();
                Integer planQty = workOrderLineBean.getPlanQty();
                //是否超领
                if (OrderModelConverter.isOverPickup(qty, actQty, workOrderLineBean.getPlanQty())) {
                    int overNum = OrderModelConverter.getOverNum(qty, actQty, planQty);
                    //记录超领数据
                    OverPickupRecordDO overPickupOrder = OrderModelConverter.createOverPickupOrder(qty,
                            overNum, orderDO.getWorkOrderSn(), TimeLimitTypeEnum.NO_LIMIT, workOrderLineBean.getPlanQty(), OverPickupTypeEnum.ORDER, orderDetailDO);
                    overPickupOrder.setFirmId(orderDO.getFirmId());
                    overPickupRecordList.add(overPickupOrder);
                }

                Integer lineStatus;
                //3.调整工单领用数量并调整工单行信息领用状态
                workOrderDetailMap.get(skuCode).setActQty(actQty + qty);
                if (workOrderDetailMap.get(skuCode).getActQty() >= planQty) {
                    lineStatus = WorkLineStatusEnum.COMPLETED.getCode();
                } else {
                    lineStatus = WorkLineStatusEnum.PART_COMPLETED.getCode();
                }
                workOrderDetailMap.get(skuCode).setStatus(lineStatus);
            }

        });
        return overPickupRecordList;
    }



    @Resource
    private AndroidSessionFacade androidSessionFacade;
    @Resource
    private RoleSkuFacade roleSkuFacade;
    @Resource
    private ParticipantRoleService participantRoleService;
    @Resource
    private WorkOrderService workOrderService;


    @Resource
    private WorkOrderDetailService workOrderDetailService;
    @Resource
    private CustomerFirmService customerFirmService;
}

